#pragma once

/*********/
/* Image */
/*********/
struct SDockerImage
{
    std::string ID;
    std::string ParentID;
    std::vector<std::string> RepoTags;
    std::vector<std::string> RepoDigests;
    time_t CreatedTimestamp;
    size_t Size;
    size_t SharedSize;
    size_t VirtualSize;
    int ContainerNum;
};

/*************/
/* Container */
/*************/
struct SDockerPortDescript
{
    std::string Type;
    unsigned short Port;

    size_t operator()(const SDockerPortDescript &PD) const //Hash
    {
        return std::hash<std::string>()(PD.Type) ^ std::hash<unsigned short>()(PD.Port);
    }
     size_t operator()(const SDockerPortDescript &PD1, const SDockerPortDescript &PD2) const //Compare
    {
        return PD1.Type == PD2.Type && PD1.Port == PD2.Port;
    }
};

struct SDockerIPPortDescript
{
    std::string IP;
    unsigned short Port;
};

struct SDockerDirectoryBind
{
    std::string HostSource; //host-src or volume-name
    std::string ContainerDestination;
    enum EMode {
        mDefault = 0x00000000,
        mRead = 0x00000001,
        mReadWrite = 0x00000003,
        mNoCopy = 0x00000004, //only applies to named volumes
    } Mode;

    SDockerDirectoryBind(const std::string &HS, const std::string &CD, EMode M = EMode::mDefault)
        : HostSource(HS), ContainerDestination(CD), Mode(M) {}
    SDockerDirectoryBind(const std::string &HS, const std::string &CD, int M = EMode::mDefault)
        : HostSource(HS), ContainerDestination(CD), Mode(static_cast<EMode>(M)) {}
};

struct SDockerHostConfig
{
    std::string NetworkMode;
    std::string IPCMode;
    std::string PIDMode;
    std::vector<SDockerDirectoryBind> Binds;
    std::unordered_map<SDockerPortDescript, std::vector<SDockerIPPortDescript>,
        SDockerPortDescript, SDockerPortDescript> PortBindings;
    bool CustomNetworkMode;
    bool Privileged; //It allows our Docker containers to access all devices (that is under the /dev folder) attached to the host
                     //as a container is not allowed to access any devices due to security reasons.

    SDockerHostConfig(void)
        : CustomNetworkMode(false), Privileged(false) {}
};

// struct SDockerNetworkSettings
// {
// };

struct SDockerMapPort
{
    std::string Type;
    std::string PublicIP;
    unsigned short PublicPort;
    unsigned short PrivatePort;
};

struct SDockerContainer
{
    std::string ID;
    std::string Image;
    std::string ImageID;
    std::string Command;
    std::string State;
    std::string Status;
    std::vector<std::string> Names;
    time_t CreatedTimestamp;
    size_t SizeRw; //The size of files that have been created or changed by this container
    size_t SizeRootFs; //The total size of all the files in this container
    std::vector<SDockerPortDescript> ExposedPorts;
    SDockerHostConfig HostConfig;
    // SDockerNetworkSettings NetworkSettings;
    std::vector<SDockerMapPort> MapPorts;
};

struct SDockerContainerProcessStatus
{
    std::vector<std::string> Titles;
    std::vector<std::vector<std::string>> vecPS;

    std::string GetPS(size_t idxRow, std::string idxCol)
    {
        int ic;
        for (ic = 0; ic < this->Titles.size(); ++ic)
        {
            if (this->Titles[ic] == idxCol)
                break;
        }
        if (ic == this->Titles.size()) return "";
        return vecPS[idxRow][ic];
    }
};

struct SDockerContainerCreation
{
    std::string Name;
    std::string Platform; //Platform in the format os[/arch[/variant]] used for image lookup.
    std::string User; //The user that commands are run as inside the container.
    bool AttachStdin;
    bool AttachStdout;
    bool AttachStderr;
    bool Tty;
    bool OpenStdin;
    bool StdinOnce;
    std::string Image;
    std::string WorkingDir;
    std::vector<std::string> Envs;
    std::vector<SDockerPortDescript> ExposedPorts;
    SDockerHostConfig HostConfig;

    SDockerContainerCreation(void)
        : AttachStdin(false), AttachStdout(true), AttachStderr(true),
        Tty(true), OpenStdin(false), StdinOnce(false)
    {}
};

struct SDockerContainerCreationResult
{
    std::string ID;
    std::vector<std::string> Warnings;
};

struct SDockerContainerRemove
{
    bool bForce; //If the container is running, kill it before removing it.
    bool bAnonymousVolumes; //Remove anonymous volumes associated with the container.
    bool bLinks; //Remove the specified link associated with the container.

    SDockerContainerRemove(void)
        : bForce(false), bAnonymousVolumes(false), bLinks(false) {}
};

/***********/
/* NetWork */
/***********/
struct SDockerNetWork
{
    std::string ID;
    std::string Name;
    std::string Driver;
    std::string Scope;
    time_t CreatedTimestamp;
    bool EnableIPv6;
    bool Internal;
    bool Attachable;
    bool Ingress;
};

/**********/
/* Volume */
/**********/
struct SDockerVolume
{
    std::string Name;
    std::string Driver;
    std::string Mountpoint;
    std::string Scope;
    time_t CreatedTimestamp;
};

struct SDockerVolumeCreation
{
    std::string Name;
    std::string Driver;

    SDockerVolumeCreation(void)
        : Driver("local") {}
};

struct SDockerVolumeCreationResult
{
    std::string Name;
    std::string Driver;
    std::string Mountpoint;
    std::string Scope;
    std::unordered_map<std::string, std::string> Options;
    std::unordered_map<std::string, std::string> Labels;
    std::unordered_map<std::string, std::string> Status;
    time_t CreatedTimestamp;
};